<template>
  <div class="page box">
    <!-- 买卖机器人配置 -->
    <div class="box bcl-bg mb-10">
      <div class="title ta-center">买卖机器人配置</div>

      <van-form @submit="saveConfig">
        <van-field
          label="池子合约地址"
          placeholder="请输入池子合约地址"
          :rules="[{ required: true, message: '请输入池子合约地址' }]"
          v-model="config.batchContractAddress"
        ></van-field>

        <van-field
          label="交易代币合约地址"
          placeholder="请输入交易代币合约地址"
          :rules="[{ required: true, message: '请输入交易代币合约地址' }]"
          v-model="config.buyToken"
        ></van-field>

        <van-field
          label="公链rpc地址"
          placeholder="请输入公链rpc地址"
          :rules="[{ required: true, message: '请输入公链rpc地址' }]"
          v-model="config.rpcUrl"
        ></van-field>

        <van-field
          label="滑点"
          placeholder="请输入滑点（0.05就代表5%）"
          :rules="[{ required: true, message: '请输入滑点' }]"
          v-model="config.slippageTolerance"
        ></van-field>

        <van-field
          label="代币合约地址"
          placeholder="请输入买卖支付的代币合约地址"
          :rules="[{ required: true, message: '请输入买卖支付的代币合约地址' }]"
          v-model="config.sellToken"
        ></van-field>

        <van-field
          label="延迟请求时间"
          placeholder="请输入延迟请求时间，单位（秒）"
          :rules="[{ required: true, message: '请输入延迟请求时间' }]"
          v-model="config.timeoutSecond"
        ></van-field>

        <div class="flex flex-rb mt-10">
          <van-button type="primary" native-type="submit">保存配置</van-button>
          <van-button type="primary" plain @click="pairInfo">
            检测池状态
          </van-button>
        </div>
      </van-form>
    </div>

    <!-- 交易池状态 -->
    <div class="box bcl-bg mb-10">
      <div class="title ta-center">交易池状态</div>

      <div>
        <span>状态：</span>
        <span>{{ transferStatus.status }}</span>
      </div>
      <div>
        <span>交易代币：</span>
        <span>{{ transferStatus.transferCoin || '--' }}</span>
      </div>
      <div>
        <span>支付代币：</span>
        <span>{{ transferStatus.payCoin || '--' }}</span>
      </div>
      <div>
        <span>价格代币：</span>
        <span>{{ transferStatus.priceCoin || '--' }}</span>
      </div>
    </div>

    <!-- 账户列表 -->
    <div class="box bcl-bg mb-10">
      <div class="flex flex-cc flex-rb mb-15">
        <van-button type="primary" @click="checkMainAmount">
          检测主网余额
        </van-button>
        <div class="title mb-0">账户列表</div>
        <van-button type="primary" @click="checkCoinAmount">
          检测代币余额
        </van-button>
      </div>

      <ul v-if="accounts.length">
        <template v-for="(v, i) in accounts" :key="i">
          <van-form class="mb-10" @submit="editAccount(i)" v-if="v.isEdit">
            <van-field
              placeholder="请输入账户私钥"
              :rules="[{ required: true, message: '请输入账户私钥' }]"
              v-model="account.privateKey"
            ></van-field>

            <van-field
              placeholder="请输入买卖数量"
              :rules="[{ required: true, message: '请输入买卖数量' }]"
              v-model="account.sellAmount"
            ></van-field>

            <van-field
              is-link
              readonly
              placeholder="请选择定时任务时间"
              @click=";(currentAccount = account), (timePickerVisible = true)"
              v-model="account.timeoutTime"
            ></van-field>

            <van-field
              placeholder="请输入买入钱包地址"
              :rules="[{ required: true, message: '请输入买入钱包地址' }]"
              v-model="account.receive"
            ></van-field>

            <div class="flex flex-rb mt-10">
              <van-button type="primary" plain @click="v.isEdit = false">
                取消
              </van-button>
              <van-button type="primary" native-type="submit">
                保存
              </van-button>
            </div>
          </van-form>

          <li class="box bcl-white rel mb-10" v-else>
            <div>
              <span>账户私钥：</span>
              <span>{{ v.privateKey }}</span>
            </div>
            <div>
              <span>买卖数量：</span>
              <span>{{ v.sellAmount }}</span>
            </div>
            <div>
              <span>主网余额：</span>
              <span>{{ v.mainAmount || '--' }}</span>
            </div>
            <div>
              <span>代币余额：</span>
              <span>{{ v.coinAmount || '--' }}</span>
            </div>
            <div>
              <span>定时任务时间：</span>
              <span>{{ v.timeoutTime || '--' }}</span>
            </div>
            <div>
              <span>买入钱包地址：</span>
              <span>{{ v.receive }}</span>
            </div>

            <!-- 编辑按钮 -->
            <div
              class="cl-primary click"
              style="position: absolute; top: 15px; right: 50px"
              @click=";(v.isEdit = true), (account = { ...v })"
            >
              编辑
            </div>

            <!-- 删除按钮 -->
            <div
              class="cl-error click"
              style="position: absolute; top: 15px; right: 15px"
              @click="delAccount(i)"
            >
              删除
            </div>
          </li>
        </template>
      </ul>

      <van-empty description="暂无数据" v-else-if="!isAdd"></van-empty>

      <van-form @submit="addAccount" v-if="isAdd">
        <van-field
          placeholder="请输入账户私钥"
          :rules="[{ required: true, message: '请输入账户私钥' }]"
          v-model="account.privateKey"
        ></van-field>

        <van-field
          placeholder="请输入买卖数量"
          :rules="[{ required: true, message: '请输入买卖数量' }]"
          v-model="account.sellAmount"
        ></van-field>

        <van-field
          is-link
          readonly
          placeholder="请选择定时任务时间"
          @click=";(currentAccount = account), (timePickerVisible = true)"
          v-model="account.timeoutTime"
        ></van-field>

        <van-field
          placeholder="请输入买入钱包地址"
          :rules="[{ required: true, message: '请输入买入钱包地址' }]"
          v-model="account.receive"
        ></van-field>

        <div class="flex flex-rb mt-10">
          <van-button type="primary" plain @click="isAdd = false">
            取消
          </van-button>
          <van-button type="primary" native-type="submit">确认添加</van-button>
        </div>
      </van-form>

      <div class="flex flex-rb" v-else>
        <van-button type="primary" @click="estimateSwap">预估交易</van-button>
        <van-button type="primary" @click="autoFillSellAmount">
          一键卖出代币
        </van-button>
        <van-button type="primary" @click="swap">下单</van-button>
        <van-button type="primary" @click="batchSwap">批量下单</van-button>
        <van-button
          type="primary"
          plain
          @click=";(isAdd = true), resetAccountModel()"
        >
          添加账户
        </van-button>
      </div>
    </div>

    <!-- 预估状态 -->
    <div class="box bcl-bg mb-10">
      <div class="title ta-center">预估状态</div>

      <div>
        <span>下单数量：</span>
        <span>{{ yuStatus.sellAmount || '--' }}</span>
      </div>
      <div>
        <span>预估收到：</span>
        <span>{{ yuStatus.buyAmount || '--' }}</span>
      </div>
    </div>

    <!-- 下单明细 -->
    <div class="box bcl-bg mb-10">
      <div class="rel">
        <div class="title ta-center" style="height: 40px; line-height: 40px">
          下单明细
        </div>
        <van-button
          style="position: absolute; top: 0; right: 0"
          type="primary"
          plain
          @click="clearOrders"
        >
          清空下单明细
        </van-button>
      </div>

      <div v-if="orders.length">
        <ul>
          <li
            class="box bcl-white rel mb-10"
            v-for="(v, i) in ordersShow"
            :key="i"
          >
            <div>
              <span>状态：</span>
              <span>{{ v.status }}</span>
            </div>
            <div>
              <span>钱包地址：</span>
              <span>{{ v.receive }}</span>
            </div>
            <div>
              <span>金额：</span>
              <span>{{ v.sellAmount }}</span>
            </div>
            <div>
              <span>时间：</span>
              <span>{{ v.createTime }}</span>
            </div>
            <div>
              <span>交易哈希：</span>
              <span>{{ v.transactionHash || '--' }}</span>
            </div>
          </li>
        </ul>

        <van-pagination
          mode="simple"
          :page-count="pageCount"
          v-model="page"
        ></van-pagination>
      </div>

      <van-empty description="暂无数据" v-else></van-empty>
    </div>

    <!-- 批量转账配置 -->
    <div class="box bcl-bg mb-10">
      <div class="title ta-center">批量转账配置</div>

      <van-form @submit="() => saveTransferConfig()">
        <van-field
          label="转账合约地址"
          placeholder="请输入批量转账合约地址"
          :rules="[{ required: true, message: '请输入批量转账合约地址' }]"
          v-model="transferConfig.batchContractAddress"
        ></van-field>

        <van-field
          label="代币合约地址"
          placeholder="请输入要转的代币合约地址"
          :rules="[{ required: true, message: '请输入要转的代币合约地址' }]"
          v-model="transferConfig.erc20Address"
        ></van-field>

        <van-field
          label="公链rpc地址"
          placeholder="请输入公链rpc地址"
          :rules="[{ required: true, message: '请输入公链rpc地址' }]"
          v-model="transferConfig.rpcUrl"
        ></van-field>

        <van-field
          label="私钥"
          placeholder="请输入私钥"
          :rules="[{ required: true, message: '请输入私钥' }]"
          v-model="transferConfig.ownerPrivate"
        ></van-field>

        <div class="flex flex-rc mt-10">
          <van-button type="primary" native-type="submit">保存配置</van-button>
        </div>
      </van-form>
    </div>

    <!-- 导入收款地址 -->
    <div class="box bcl-bg mb-10">
      <div class="title ta-center">导入收款地址</div>

      <div class="flex flex-rc mt-10">
        <van-uploader accept=".txt" :after-read="importTxtFile">
          <van-button type="primary" icon="plus">上传文件</van-button>
        </van-uploader>
      </div>

      <div class="ta-center mt-10" v-if="transferConfig.amountList.length">
        <div>{{ transferConfig.amountList }}</div>
        <div>{{ transferConfig.toList }}</div>
      </div>

      <div class="flex flex-rc mt-10" v-if="transferConfig.amountList.length">
        <van-button type="primary" @click="batchTransfer">执行转账</van-button>
      </div>
    </div>

    <!-- 时分秒选择器 -->
    <van-popup position="bottom" v-model:show="timePickerVisible">
      <van-time-picker
        title="选择时间"
        :columns-type="['hour', 'minute', 'second']"
        @cancel="timePickerVisible = false"
        @confirm="onTimeSelect"
      ></van-time-picker
    ></van-popup>
  </div>
</template>

<script setup>
import { ref, watch, computed } from 'vue'
import { showToast, formatDateTime } from 'js/utils'
import api from 'js/api'

// 买卖机器人配置
const config = ref(
  localStorage.getItem('config')
    ? JSON.parse(localStorage.getItem('config'))
    : {
        batchContractAddress: '',
        buyToken: '',
        rpcUrl: '',
        slippageTolerance: '',
        sellToken: '',
        timeoutSecond: '',
      }
)

// 交易池状态
const transferStatus = ref(
  localStorage.getItem('transferStatus')
    ? JSON.parse(localStorage.getItem('transferStatus'))
    : {
        status: '待检测',
        transferCoin: '',
        payCoin: '',
        priceCoin: '',
      }
)

// 账户列表
const account = ref({
  privateKey: '',
  sellAmount: '',
  mainAmount: '',
  coinAmount: '',
  timeoutTime: '',
  receive: '',
})
const accounts = ref(
  localStorage.getItem('accounts')
    ? JSON.parse(localStorage.getItem('accounts'))
    : []
)
const currentAccount = ref({})
const isAdd = ref(false)

// 预估状态
const yuStatus = ref(
  localStorage.getItem('yuStatus')
    ? JSON.parse(localStorage.getItem('yuStatus'))
    : {
        sellAmount: '',
        buyAmount: '',
      }
)

// 下单明细
const orders = ref(
  localStorage.getItem('orders')
    ? JSON.parse(localStorage.getItem('orders'))
    : []
)
const page = ref(1)
const pageSize = ref(2)
const pageCount = computed(() => {
  return Math.ceil(orders.value.length / pageSize.value)
})
const ordersShow = computed(() => {
  return orders.value.length
    ? orders.value.slice(
        (page.value - 1) * pageSize.value,
        page.value * pageSize.value
      )
    : []
})

// 批量转账配置
const transferConfig = ref(
  localStorage.getItem('transferConfig')
    ? JSON.parse(localStorage.getItem('transferConfig'))
    : {
        batchContractAddress: '',
        erc20Address: '',
        rpcUrl: '',
        ownerPrivate: '',
        amountList: [],
        toList: [],
      }
)

// 时间选择
const timePickerVisible = ref(false)

// 保存配置
function saveConfig() {
  localStorage.setItem('config', JSON.stringify(config.value))
  showToast('保存成功')
}

// 检测池状态
async function pairInfo() {
  const params = {
    ...config.value,
  }

  delete params.slippageTolerance

  const { code, data } = await api.pairInfo(params)

  if (code === 200) {
    transferStatus.value = {
      status: '已开启',
      transferCoin: data.tokenAAmount + ' ' + data.tokenASymbol,
      payCoin: data.tokenBAmount + ' ' + data.tokenBSymbol,
      priceCoin: data.tokenAAmount / data.tokenBAmount,
    }
  } else {
    transferStatus.value = {
      status: '未开启',
      transferCoin: '',
      payCoin: '',
      priceCoin: '',
    }
  }

  localStorage.setItem('transferStatus', JSON.stringify(transferStatus.value))
}

// 添加账户
function addAccount() {
  const accountIndex = accounts.value.findIndex(
    (v) => v.receive === account.value.receive
  )

  if (accountIndex === -1) {
    accounts.value.push(account.value)
    localStorage.setItem('accounts', JSON.stringify(accounts.value))
    isAdd.value = false
    showToast('添加成功')
  } else {
    showToast('已存在该买入钱包地址，请修改')
  }
}

// 编辑账户
function editAccount(index) {
  const accountIndex = accounts.value.findIndex(
    (v) => v.receive === account.value.receive
  )

  if (accountIndex === -1 || accountIndex === index) {
    accounts.value[index] = account.value
    accounts.value[index].isEdit = false
    localStorage.setItem('accounts', JSON.stringify(accounts.value))
    showToast('保存成功')
  } else {
    showToast('已存在该买入钱包地址，请修改')
  }
}

// 删除账户
function delAccount(index) {
  accounts.value.splice(index, 1)
  localStorage.setItem('accounts', JSON.stringify(accounts.value))
  showToast('删除成功')
}

// 当一个账户里面数据变更，替换缓存
function changeOneAccount(account) {
  const accountIndex = accounts.value.findIndex(
    (v) => v.receive === account.receive
  )

  if (accountIndex !== -1) {
    accounts.value[accountIndex] = account
  }

  localStorage.setItem('accounts', JSON.stringify(accounts.value))
}

// 初始化账户表单模型
function resetAccountModel() {
  account.value = {
    privateKey: '',
    sellAmount: '',
    mainAmount: '',
    coinAmount: '',
    timeoutTime: '',
    receive: '',
  }
}

// 检测主网余额
function checkMainAmount() {
  if (accounts.value.length === 0) {
    return showToast('请先添加账户')
  }

  for (let i = 0; i < accounts.value.length; i++) {
    const account = accounts.value[i]

    const params = {
      rpcUrl: config.value.rpcUrl,
      walletAddress: account.receive,
    }

    api.ethBalance(params).then(({ code, data }) => {
      if (code === 200) {
        account.mainAmount = data
        changeOneAccount(account)
      }
    })
  }
}

// 检测代币余额
function checkCoinAmount() {
  if (accounts.value.length === 0) {
    return showToast('请先添加账户')
  }

  for (let i = 0; i < accounts.value.length; i++) {
    const account = accounts.value[i]

    const params = {
      tokenContract: config.value.sellToken,
      rpcUrl: config.value.rpcUrl,
      walletAddress: account.receive,
    }

    api.tokenBalance(params).then(({ code, data }) => {
      if (code === 200) {
        account.coinAmount = data
        changeOneAccount(account)
      }
    })
  }
}

// 预估交易
async function estimateSwap() {
  if (accounts.value.length === 0) {
    return showToast('请先添加账户')
  }

  const params = {
    ...config.value,
    sellAmount: accounts.value
      .map((v) => v.sellAmount)
      .reduce((a, b) => Number(a) + Number(b)),
  }

  delete params.slippageTolerance

  const { code, data } = await api.estimateSwap(params)

  if (code === 200) {
    yuStatus.value = {
      sellAmount: data.sellAmount,
      buyAmount: data.buyAmount,
    }
  }

  localStorage.setItem('yuStatus', JSON.stringify(yuStatus.value))
}

// 一键卖出代币
function autoFillSellAmount() {
  if (accounts.value.length === 0) {
    return showToast('请先添加账户')
  }

  for (let i = 0; i < accounts.value.length; i++) {
    const account = accounts.value[i]
    account.sellAmount = account.coinAmount
  }

  localStorage.setItem('accounts', JSON.stringify(accounts.value))
}

// 下单
async function swap() {
  if (accounts.value.length === 0) {
    return showToast('请先添加账户')
  }

  for (let i = 0; i < accounts.value.length; i++) {
    const account = accounts.value[i]

    if (account.sellAmount) {
      await doSwap(account)
    }
  }
}

// 执行下单
function doSwap(account) {
  return new Promise(async (resolve) => {
    const configTimeoutSecond = (config.value.timeoutSecond || 0) * 1000

    const params = {
      ...config.value,
      ...account,
    }

    if (params.timeoutTime) {
      const [hour, minute, second] = params.timeoutTime.split(':')
      params.hour = hour
      params.minute = minute
      params.second = second
    }

    const { code, data } = account.timeoutTime
      ? await api.swapTask(params)
      : await api.swap(params)

    const status = code === 200 ? '成功' : '失败'

    const timeoutSecond =
      code === 200
        ? configTimeoutSecond
        : configTimeoutSecond >= 2000
        ? configTimeoutSecond
        : 2000

    if (!account.timeoutTime) {
      // 延时任务不需要记录下单明细
      orders.value.push({
        status,
        receive: account.receive,
        sellAmount: account.sellAmount,
        createTime: formatDateTime(Date.now()),
        transactionHash: data?.transactionHash,
      })

      localStorage.setItem('orders', JSON.stringify(orders.value))
    }

    setTimeout(resolve, timeoutSecond)
  })
}

// 批量下单
async function batchSwap() {
  if (accounts.value.length === 0) {
    return showToast('请先添加账户')
  }

  const params = {
    ...config.value,
    swapParamsDTOList: accounts.value.map((v) => {
      return {
        privateKey: v.privateKey,
        amount: v.sellAmount,
        receive: v.receive,
      }
    }),
  }

  delete params.timeoutSecond

  const { code, data } = await api.batchSwap(params)

  if (code === 200) {
  }
}

// 清空下单明细
function clearOrders() {
  orders.value = []
  localStorage.setItem('orders', JSON.stringify(orders.value))
}

// 保存批量转账配置
function saveTransferConfig(msg = '保存成功') {
  localStorage.setItem('transferConfig', JSON.stringify(transferConfig.value))
  showToast(msg)
}

// 执行批量转账
async function batchTransfer() {
  const params = {
    ...transferConfig.value,
  }

  const { code, data } = await api.batchTransfer(params)

  if (code === 200) {
  }
}

// 导入TXT文件
function importTxtFile({ file }) {
  try {
    const reader = new FileReader()
    reader.readAsText(file)
    reader.onload = () => {
      const result = reader.result.replace(/\r/g, '')
      const rows = result
        .split('\n')
        .filter((v) => v)
        .map((v) => JSON.parse(v))
      const [amountList = [], toList = []] = rows

      if (amountList.length !== toList.length) {
        return showToast('转账金额跟转账地址数量不一致，请修改后重新上传')
      }

      transferConfig.value.amountList = amountList
      transferConfig.value.toList = toList
      saveTransferConfig('上传成功')
    }
  } catch (err) {
    showToast('上传失败，请检查数据格式是否正确')
  }
}

// 选择时间
function onTimeSelect({ selectedValues }) {
  const [hour, minute, second] = selectedValues
  currentAccount.value.timeoutTime = `${hour}:${minute}:${second}`
  timePickerVisible.value = false
}
</script>

<style lang="scss">
@import 'style/index.scss';

.van-button {
  width: 100px;
  height: 40px;
  padding: 0;
}

.van-form {
  .van-field {
    &__label {
      label {
        font-size: var(--font-size) !important;
      }
    }

    &__value {
      input {
        font-size: var(--font-size) !important;
      }
    }
  }
}
</style>
